#include "XComponentBackend.h"
#include "GameStreamManager.h"
#include "core/utils/LimelightUtils.h"
#include "video/VideoProcessor.h"
#include "core/utils/XComponentUtils.h"
#include "control/touch_screen/AbstractTouchScreenControlHandler.h"
#include "control/mouse/MouseController.h"
#include "control/keyboard/KeyboardController.h"
#include <native_window/external_window.h>
#include <native_image/graphic_error_code.h>

#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN  0x0
#define LOG_TAG     "XComponentCallbacks"
#include <hilog/log.h>


void XComponentBackend::XComponentCallbacks::OnSurfaceCreated(OH_NativeXComponent *comp, void *win) {
    GameStreamManager::nativeWindow = reinterpret_cast<OHNativeWindow*>(win);
    if (int nativeError = OH_NativeWindow_NativeWindowSetScalingModeV2(GameStreamManager::nativeWindow, OH_SCALING_MODE_SCALE_TO_WINDOW_V2); nativeError != NATIVE_ERROR_OK) {
        OH_LOG_WARN(LOG_APP, "Failed to set native window scaling mode");
        return;
    }
}

void XComponentBackend::XComponentCallbacks::OnSurfaceChanged(OH_NativeXComponent *comp, void *win) {
}

void XComponentBackend::XComponentCallbacks::OnSurfaceDestroyed(OH_NativeXComponent *comp, void *win) {
    const auto id = XComponentUtils::getId(comp);
    if (!id) {
        return;
    }
    if constexpr (DEBUG) {
        OH_LOG_DEBUG(LOG_APP, "OnSurfaceDestroyed triggered for XComponent id %{public}s", id->c_str());
    }
    GameStreamManager::cleanup();
}

void XComponentBackend::XComponentCallbacks::DispatchTouchEvent(OH_NativeXComponent *comp, void *win) {
    OH_NativeXComponent_TouchEvent touchEvent;
    XCOMP_CALL_OR_ELSE(GetTouchEvent(comp, win, &touchEvent), return);
    INIT_XCOMPONENT_SELF_OR_ELSE(return);
    if (self.touchHandler) {
        self.touchHandler->handle(comp, win, touchEvent);
    }
}

void XComponentBackend::XComponentCallbacks::DispatchMouseEvent(OH_NativeXComponent *comp, void *win) {
    OH_NativeXComponent_MouseEvent mouseEvent;
    XCOMP_CALL_OR_ELSE(GetMouseEvent(comp, win, &mouseEvent), return);
    INIT_XCOMPONENT_SELF_OR_ELSE(return);
    if (self.mouseController) {
        self.mouseController->handle(comp, win, mouseEvent);
    }
}

void XComponentBackend::XComponentCallbacks::DispatchHoverEvent(OH_NativeXComponent *comp, bool isHover) {
    // TODO
}

bool XComponentBackend::XComponentCallbacks::KeyEventCallback(OH_NativeXComponent *comp, void *win) {
    INIT_XCOMPONENT_SELF_OR_ELSE(return false);
    OH_NativeXComponent_KeyEvent *keyEvent;
    XCOMP_RETURN_IF_NOT_OK(false, GetKeyEvent(comp, &keyEvent));
    if (self.keyboardController) {
        return self.keyboardController->handle(comp, win, *keyEvent);
    }
    return false;
}

void XComponentBackend::XComponentCallbacks::UIInputAxisEventCallback(OH_NativeXComponent *comp,
        ArkUI_UIInputEvent *event, ArkUI_UIInputEvent_Type type) {
    int32_t sourceType = OH_ArkUI_UIInputEvent_GetSourceType(event);
    double yVal = OH_ArkUI_AxisEvent_GetVerticalAxisValue(event);
    double xVal = OH_ArkUI_AxisEvent_GetHorizontalAxisValue(event);
    if constexpr (DEBUG) {
        OH_LOG_DEBUG(LOG_APP, "caught ui axis event, source type %{public}d, dx %{public}f, dy %{public}f",
            sourceType, xVal, yVal);
    }
    if (std::abs(xVal) > 1e-3) {
        LI_CALL_OR_ELSE(SendHScrollEvent(xVal / scrollValuePerClick), return);
    }
    if (std::abs(yVal) > 1e-3) {
        LI_CALL_OR_ELSE(SendScrollEvent(-yVal / scrollValuePerClick), return);
    }
}
